import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from math import sqrt

# --------------------------
# 1. 数据读取与预处理
# --------------------------
def load_garden_route(csv_path):
    """读取个园路线CSV文件，返回X、Y坐标数组（过滤无效数据）"""
    # 读取CSV，确保列名为'x'和'y'（与输入文件格式匹配）
    df = pd.read_csv(csv_path)
    # 移除空值行，避免计算错误
    df_clean = df.dropna(subset=['x', 'y']).reset_index(drop=True)
    # 提取坐标数组
    x_coords = df_clean['x'].values
    y_coords = df_clean['y'].values
    print(f"成功读取个园路线数据，共{len(x_coords)}个坐标点")
    return x_coords, y_coords

# --------------------------
# 2. 趣味性核心指标计算
# --------------------------
def calculate_fun_metrics(x, y):
    """
    计算个园路线的3个核心趣味性指标：
    1. 曲折度：总路径长度 / 起点-终点直线距离（反映路线“幽深感”，值越大越曲折）
    2. 景观覆盖率：路线覆盖的核心节点数 / 个园核心节点总数（反映“游览价值”）
    3. 空间节奏变化率：方向变化次数（>30°）/ 总坐标点数（反映“移步换景”频率）
    """
    # （1）计算曲折度
    # 总路径长度（累加每段坐标的欧式距离）
    total_path = 0.0
    for i in range(1, len(x)):
        dx = x[i] - x[i-1]
        dy = y[i] - y[i-1]
        total_path += sqrt(dx**2 + dy**2)
    # 起点-终点直线距离
    start_end_dist = sqrt((x[-1] - x[0])**2 + (y[-1] - y[0])**2)
    # 避免除以0（极端情况：起点=终点）
    tortuosity = round(total_path / start_end_dist if start_end_dist != 0 else 0, 2)

    # （2）计算景观覆盖率（基于个园实际核心节点坐标范围）
    # 个园核心节点：入口、抱山楼、夏山、秋山、服务用房（参考园林平面图设定）
    core_nodes = {
        "入口": (11.5, 12.5, 14.5, 15.5),    # (x_min, x_max, y_min, y_max)
        "抱山楼": (3.0, 4.2, 26.4, 27.6),
        "夏山": (11.4, 12.6, 52.8, 54.0),
        "秋山": (17.4, 18.6, 62.4, 63.6),
        "服务用房": (23.4, 24.6, 72.6, 73.8)
    }
    covered_nodes = 0
    # 检查每个核心节点是否有路线坐标覆盖
    for node, (x_min, x_max, y_min, y_max) in core_nodes.items():
        for xi, yi in zip(x, y):
            if x_min <= xi <= x_max and y_min <= yi <= y_max:
                covered_nodes += 1
                break  # 覆盖一个即可，无需重复计数
    coverage_rate = round(covered_nodes / len(core_nodes), 2)

    # （3）计算空间节奏变化率
    direction_change_count = 0
    # 至少3个点才会有方向变化
    if len(x) >= 3:
        for i in range(1, len(x)-1):
            # 前一段向量（i-1到i）
            vec1 = (x[i] - x[i-1], y[i] - y[i-1])
            # 后一段向量（i到i+1）
            vec2 = (x[i+1] - x[i], y[i+1] - y[i])
            # 计算两向量的夹角（弧度转角度）
            dot_product = vec1[0] * vec2[0] + vec1[1] * vec2[1]
            norm1 = sqrt(vec1[0]**2 + vec1[1]**2)
            norm2 = sqrt(vec2[0]**2 + vec2[1]**2)
            # 避免acos参数超出[-1,1]（浮点误差）
            cos_theta = max(min(dot_product / (norm1 * norm2) if (norm1 * norm2) != 0 else 1, 1), -1)
            angle_deg = np.degrees(np.arccos(cos_theta))
            # 角度差>30°计为一次方向变化
            if angle_deg > 30:
                direction_change_count += 1
    rhythm_rate = round(direction_change_count / len(x) if len(x) != 0 else 0, 2)

    # 返回指标字典
    return {
        "曲折度": tortuosity,
        "景观覆盖率": coverage_rate,
        "空间节奏变化率": rhythm_rate
    }

# --------------------------
# 3. 可视化图表生成
# --------------------------
def plot_garden_analysis(x, y, metrics):
    """
    生成2个子图的可视化图表：
    左图：个园路线空间分布（标注核心节点）
    右图：趣味性指标数值展示（柱状图）
    """
    # 中文显示配置
    plt.rcParams['font.sans-serif'] = ['SimHei', 'DejaVu Sans']
    plt.rcParams['axes.unicode_minus'] = False

    # 创建画布（1行2列，宽15英寸，高6英寸）
    fig, ( ax2) = plt.subplots(1, 1, figsize=(15, 6))

    
    # （2）右图：趣味性指标柱状图
    # 提取指标名称与数值
    metric_names = list(metrics.keys())
    metric_values = list(metrics.values())
    # 设置柱状图颜色（渐变蓝）
    colors = ['#3498db', '#2980b9', '#1f618d']
    # 绘制柱状图
    bars = ax2.bar(metric_names, metric_values, color=colors, edgecolor='black', linewidth=1)
    # 在柱子顶部添加数值标签
    for bar, value in zip(bars, metric_values):
        height = bar.get_height()
        ax2.text(
            bar.get_x() + bar.get_width()/2., height + 0.02,
            str(value), ha='center', va='bottom',
            fontsize=12, fontweight='bold'
        )
    # 坐标轴与标题
    ax2.set_ylabel('指标数值', fontsize=11)
    ax2.set_title('个园趣味性路线核心指标', fontsize=13, fontweight='bold', pad=20)
    ax2.set_ylim(0, max(metric_values) * 1.2)  # 纵轴范围（预留数值标签空间）
    ax2.grid(True, alpha=0.3, axis='y')  # 仅纵轴网格

    # 调整子图间距，避免文字重叠
    plt.tight_layout()
    # 保存图表（高分辨率：300dpi，支持透明背景）
    plt.savefig('个园_趣味性路线分析图.png', dpi=300, bbox_inches='tight', facecolor='white')
    print("图表已保存为：个园_趣味性路线分析图.png")
    # 显示图表（运行时可选）
    plt.show()

# --------------------------
# 4. 主函数（流程串联）
# --------------------------
def main():
    # 1. 读取个园路线数据（需替换为你的CSV文件实际路径）
    csv_file_path = "out_problem1/个园_fun_route.csv"  # 关键：替换为正确路径
    try:
        x_coords, y_coords = load_garden_route(csv_file_path)
    except FileNotFoundError:
        print(f"错误：未找到文件 {csv_file_path}，请检查路径是否正确！")
        return

    # 2. 计算趣味性指标
    fun_metrics = calculate_fun_metrics(x_coords, y_coords)
    # 打印指标结果
    print("\n" + "="*50)
    print("个园趣味性路线指标计算结果")
    print("="*50)
    for metric, value in fun_metrics.items():
        print(f"• {metric}：{value}")
    print("="*50 + "\n")

    # 3. 生成可视化图表
    plot_garden_analysis(x_coords, y_coords, fun_metrics)

# 执行主函数
if __name__ == "__main__":
    main()